#include "common.h"

int server = 0;
int port = 8000;
char hostname[32];
int length = 65536;

void server_routine();
void client_routine();
void* process(void*);

int main(int argc, char* argv[]) {
	Args args = parsecmdline(argc, argv);
	if (args.empty() || args.find("h") == args.end()) {
		printf("Usage: %s [-s] <-h hostname> [-p port] [-l length]\n", argv[0]);
		return 1;
	}
 
	strcpy(hostname, args["h"].c_str());
	if (args.find("s") != args.end()) server = 1;
	if (args.find("p") != args.end()) port = atoi(args["p"].c_str());
	if (args.find("l") != args.end()) length = atoi(args["l"].c_str());


	if (server) {
		server_routine();
	}
	else {
		client_routine();
	}
	return 0;
}

void server_routine() {
  int listenfd, clientfd, ret, len;
	int *fd;
	pthread_t th;
  struct sockaddr_in servaddr, cliaddr;
	socklen_t servaddrlen, cliaddrlen;

	servaddr = resolve(hostname, port);

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) ERR_EXIT("socket");

	ret  = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0) ERR_EXIT("bind");

	ret = listen(listenfd, 5);
	if (ret < 0) ERR_EXIT("listen");

	while(1) {
		cliaddrlen = sizeof(cliaddr);
		clientfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen);
		if (clientfd < 0) ERR_EXIT("accept");
		printf("%s:%d come in\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
		fd = (int*)malloc(sizeof(int));
		*fd = clientfd;
    ret = pthread_create(&th, NULL, process, (void*)fd);
	}
}

void client_routine() {
	int sockfd, ret;
  struct sockaddr_in servaddr;
	char *buf;

	buf = (char*)malloc(length);
	assert(buf);

	servaddr = resolve(hostname, port);
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) ERR_EXIT("socket");

	ret = connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0) ERR_EXIT("connect");
  
	writen(sockfd, buf, length);
	readn(sockfd, buf, length);
}

void* process(void *arg) {
	int clientfd, n;
	char *buf;

  buf	= (char*)malloc(4096);;
  assert(buf);
  clientfd = *(int*)arg;

	printf("thread %d started\n", pthread_self());
	while(1) {
		n = readn(clientfd, buf, 4096);
		writen(clientfd, buf, n);
		if (n < 4096) break;
	}
	printf("thread %d ended\n", pthread_self());

	free(buf);
	free(arg);
	close(clientfd);
}
